home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / hack / 1 / src / dog.c < prev    next >
Encoding:
C/C++ Source or Header  |  1985-07-26  |  10.2 KB  |  414 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  2. /* hack.dog.c - version 1.0.3 */
  3.  
  4. #include    "hack.h"
  5. #include    "hack.mfndpos.h"
  6. extern struct monst *makemon();
  7. #include "def.edog.h"
  8. #include "def.mkroom.h"
  9.  
  10. struct permonst li_dog =
  11.     { "little dog", 'd',2,18,6,1,6,sizeof(struct edog) };
  12. struct permonst dog =
  13.     { "dog", 'd',4,16,5,1,6,sizeof(struct edog) };
  14. struct permonst la_dog =
  15.     { "large dog", 'd',6,15,4,2,4,sizeof(struct edog) };
  16.  
  17.  
  18. makedog(){
  19. register struct monst *mtmp = makemon(&li_dog,u.ux,u.uy);
  20.     if(!mtmp) return; /* dogs were genocided */
  21.     initedog(mtmp);
  22. }
  23.  
  24. initedog(mtmp) register struct monst *mtmp; {
  25.     mtmp->mtame = mtmp->mpeaceful = 1;
  26.     EDOG(mtmp)->hungrytime = 1000 + moves;
  27.     EDOG(mtmp)->eattime = 0;
  28.     EDOG(mtmp)->droptime = 0;
  29.     EDOG(mtmp)->dropdist = 10000;
  30.     EDOG(mtmp)->apport = 10;
  31.     EDOG(mtmp)->whistletime = 0;
  32. }
  33.  
  34. /* attach the monsters that went down (or up) together with @ */
  35. struct monst *mydogs = 0;
  36. struct monst *fallen_down = 0;    /* monsters that fell through a trapdoor */
  37.     /* they will appear on the next level @ goes to, even if he goes up! */
  38.  
  39. losedogs(){
  40. register struct monst *mtmp;
  41.     while(mtmp = mydogs){
  42.         mydogs = mtmp->nmon;
  43.         mtmp->nmon = fmon;
  44.         fmon = mtmp;
  45.         mnexto(mtmp);
  46.     }
  47.     while(mtmp = fallen_down){
  48.         fallen_down = mtmp->nmon;
  49.         mtmp->nmon = fmon;
  50.         fmon = mtmp;
  51.         rloc(mtmp);
  52.     }
  53. }
  54.  
  55. keepdogs(){
  56. register struct monst *mtmp;
  57.     for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
  58.         if(dist(mtmp->mx,mtmp->my) < 3 && follower(mtmp)
  59.         && !mtmp->msleep && !mtmp->mfroz) {
  60.         relmon(mtmp);
  61.         mtmp->nmon = mydogs;
  62.         mydogs = mtmp;
  63.         unpmon(mtmp);
  64.         keepdogs();    /* we destroyed the link, so use recursion */
  65.         return;        /* (admittedly somewhat primitive) */
  66.     }
  67. }
  68.  
  69. fall_down(mtmp) register struct monst *mtmp; {
  70.     relmon(mtmp);
  71.     mtmp->nmon = fallen_down;
  72.     fallen_down = mtmp;
  73.     unpmon(mtmp);
  74.     mtmp->mtame = 0;
  75. }
  76.  
  77. /* return quality of food; the lower the better */
  78. #define    DOGFOOD    0
  79. #define    CADAVER    1
  80. #define    ACCFOOD    2
  81. #define    MANFOOD    3
  82. #define    APPORT    4
  83. #define    POISON    5
  84. #define    UNDEF    6
  85. dogfood(obj) register struct obj *obj; {
  86.     switch(obj->olet) {
  87.     case FOOD_SYM:
  88.         return(
  89.         (obj->otyp == TRIPE_RATION) ? DOGFOOD :
  90.         (obj->otyp < CARROT) ? ACCFOOD :
  91.         (obj->otyp < CORPSE) ? MANFOOD :
  92.         (poisonous(obj) || obj->age + 50 <= moves ||
  93.             obj->otyp == DEAD_COCKATRICE)
  94.             ? POISON : CADAVER
  95.         );
  96.     default:
  97.         if(!obj->cursed) return(APPORT);
  98.         /* fall into next case */
  99.     case BALL_SYM:
  100.     case CHAIN_SYM:
  101.     case ROCK_SYM:
  102.         return(UNDEF);
  103.     }
  104. }
  105.  
  106. /* return 0 (no move), 1 (move) or 2 (dead) */
  107. dog_move(mtmp, after) register struct monst *mtmp; {
  108. register int nx,ny,omx,omy,appr,nearer,j;
  109. int udist,chi,i,whappr;
  110. register struct monst *mtmp2;
  111. register struct permonst *mdat = mtmp->data;
  112. register struct edog *edog = EDOG(mtmp);
  113. struct obj *obj;
  114. struct trap *trap;
  115. xchar cnt,chcnt,nix,niy;
  116. schar dogroom,uroom;
  117. xchar gx,gy,gtyp,otyp;    /* current goal */
  118. coord poss[9];
  119. int info[9];
  120. #define GDIST(x,y) ((x-gx)*(x-gx) + (y-gy)*(y-gy))
  121. #define DDIST(x,y) ((x-omx)*(x-omx) + (y-omy)*(y-omy))
  122.  
  123.     if(moves <= edog->eattime) return(0);    /* dog is still eating */
  124.     omx = mtmp->mx;
  125.     omy = mtmp->my;
  126.     whappr = (moves - EDOG(mtmp)->whistletime < 5);
  127.     if(moves > edog->hungrytime + 500 && !mtmp->mconf){
  128.         mtmp->mconf = 1;
  129.         mtmp->mhpmax /= 3;
  130.         if(mtmp->mhp > mtmp->mhpmax)
  131.             mtmp->mhp = mtmp->mhpmax;
  132.         if(cansee(omx,omy))
  133.             pline("%s is confused from hunger.", Monnam(mtmp));
  134.         else    pline("You feel worried about %s.", monnam(mtmp));
  135.     } else
  136.     if(moves > edog->hungrytime + 750 || mtmp->mhp < 1){
  137.         if(cansee(omx,omy))
  138.             pline("%s dies from hunger.", Monnam(mtmp));
  139.         else
  140.         pline("You have a sad feeling for a moment, then it passes.");
  141.         mondied(mtmp);
  142.         return(2);
  143.     }
  144.     dogroom = inroom(omx,omy);
  145.     uroom = inroom(u.ux,u.uy);
  146.     udist = dist(omx,omy);
  147.  
  148.     /* maybe we tamed him while being swallowed --jgm */
  149.     if(!udist) return(0);
  150.  
  151.     /* if we are carrying sth then we drop it (perhaps near @) */
  152.     /* Note: if apport == 1 then our behaviour is independent of udist */
  153.     if(mtmp->minvent){
  154.         if(!rn2(udist) || !rn2((int) edog->apport))
  155.         if(rn2(10) < edog->apport){
  156.             relobj(mtmp, (int) mtmp->minvis);
  157.             if(edog->apport > 1) edog->apport--;
  158.             edog->dropdist = udist;        /* hpscdi!jon */
  159.             edog->droptime = moves;
  160.         }
  161.     } else {
  162.         if(obj = o_at(omx,omy)) if(!index("0_", obj->olet)){
  163.             if((otyp = dogfood(obj)) <= CADAVER){
  164.             nix = omx;
  165.             niy = omy;
  166.             goto eatobj;
  167.             }
  168.             if(obj->owt < 10*mtmp->data->mlevel)
  169.             if(rn2(20) < edog->apport+3)
  170.             if(rn2(udist) || !rn2((int) edog->apport)){
  171.             freeobj(obj);
  172.             unpobj(obj);
  173.             /* if(levl[omx][omy].scrsym == obj->olet)
  174.                 newsym(omx,omy); */
  175.             mpickobj(mtmp,obj);
  176.             }
  177.         }
  178.     }
  179.  
  180.     /* first we look for food */
  181.     gtyp = UNDEF;    /* no goal as yet */
  182. #ifdef LINT
  183.     gx = gy = 0;    /* suppress 'used before set' message */
  184. #endif LINT
  185.     for(obj = fobj; obj; obj = obj->nobj) {
  186.         otyp = dogfood(obj);
  187.         if(otyp > gtyp || otyp == UNDEF) continue;
  188.         if(inroom(obj->ox,obj->oy) != dogroom) continue;
  189.         if(otyp < MANFOOD &&
  190.          (dogroom >= 0 || DDIST(obj->ox,obj->oy) < 10)) {
  191.             if(otyp < gtyp || (otyp == gtyp &&
  192.                 DDIST(obj->ox,obj->oy) < DDIST(gx,gy))){
  193.                 gx = obj->ox;
  194.                 gy = obj->oy;
  195.                 gtyp = otyp;
  196.             }
  197.         } else
  198.         if(gtyp == UNDEF && dogroom >= 0 &&
  199.            uroom == dogroom &&
  200.            !mtmp->minvent && edog->apport > rn2(8)){
  201.             gx = obj->ox;
  202.             gy = obj->oy;
  203.             gtyp = APPORT;
  204.         }
  205.     }
  206.     if(gtyp == UNDEF ||
  207.       (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)){
  208.         if(dogroom < 0 || dogroom == uroom){
  209.             gx = u.ux;
  210.             gy = u.uy;
  211. #ifndef QUEST
  212.         } else {
  213.             int tmp = rooms[dogroom].fdoor;
  214.                 cnt = rooms[dogroom].doorct;
  215.  
  216.             gx = gy = FAR;    /* random, far away */
  217.             while(cnt--){
  218.                 if(dist(gx,gy) >
  219.                 dist(doors[tmp].x, doors[tmp].y)){
  220.                     gx = doors[tmp].x;
  221.                     gy = doors[tmp].y;
  222.                 }
  223.                 tmp++;
  224.             }
  225.             /* here gx == FAR e.g. when dog is in a vault */
  226.             if(gx == FAR || (gx == omx && gy == omy)){
  227.                 gx = u.ux;
  228.                 gy = u.uy;
  229.             }
  230. #endif QUEST
  231.         }
  232.         appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
  233.         if(after && udist <= 4 && gx == u.ux && gy == u.uy)
  234.             return(0);
  235.         if(udist > 1){
  236.             if(!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||
  237.                whappr ||
  238.                (mtmp->minvent && rn2((int) edog->apport)))
  239.                 appr = 1;
  240.         }
  241.         /* if you have dog food he'll follow you more closely */
  242.         if(appr == 0){
  243.             obj = invent;
  244.             while(obj){
  245.                 if(obj->otyp == TRIPE_RATION){
  246.                     appr = 1;
  247.                     break;
  248.                 }
  249.                 obj = obj->nobj;
  250.             }
  251.         }
  252.     } else    appr = 1;    /* gtyp != UNDEF */
  253.     if(mtmp->mconf) appr = 0;
  254.  
  255.     if(gx == u.ux && gy == u.uy && (dogroom != uroom || dogroom < 0)){
  256.     extern coord *gettrack();
  257.     register coord *cp;
  258.         cp = gettrack(omx,omy);
  259.         if(cp){
  260.             gx = cp->x;
  261.             gy = cp->y;
  262.         }
  263.     }
  264.  
  265.     nix = omx;
  266.     niy = omy;
  267.     cnt = mfndpos(mtmp,poss,info,ALLOW_M | ALLOW_TRAPS);
  268.     chcnt = 0;
  269.     chi = -1;
  270.     for(i=0; i<cnt; i++){
  271.         nx = poss[i].x;
  272.         ny = poss[i].y;
  273.         if(info[i] & ALLOW_M){
  274.             mtmp2 = m_at(nx,ny);
  275.             if(mtmp2->data->mlevel >= mdat->mlevel+2 ||
  276.               mtmp2->data->mlet == 'c')
  277.                 continue;
  278.             if(after) return(0); /* hit only once each move */
  279.  
  280.             if(hitmm(mtmp, mtmp2) == 1 && rn2(4) &&
  281.               mtmp2->mlstmv != moves &&
  282.               hitmm(mtmp2,mtmp) == 2) return(2);
  283.             return(0);
  284.         }
  285.  
  286.         /* dog avoids traps */
  287.         /* but perhaps we have to pass a trap in order to follow @ */
  288.         if((info[i] & ALLOW_TRAPS) && (trap = t_at(nx,ny))){
  289.             if(!trap->tseen && rn2(40)) continue;
  290.             if(rn2(10)) continue;
  291.         }
  292.  
  293.         /* dog eschewes cursed objects */
  294.         /* but likes dog food */
  295.         obj = fobj;
  296.         while(obj){
  297.             if(obj->ox != nx || obj->oy != ny)
  298.             goto nextobj;
  299.             if(obj->cursed) goto nxti;
  300.             if(obj->olet == FOOD_SYM &&
  301.             (otyp = dogfood(obj)) < MANFOOD &&
  302.             (otyp < ACCFOOD || edog->hungrytime <= moves)){
  303.             /* Note: our dog likes the food so much that he
  304.             might eat it even when it conceals a cursed object */
  305.             nix = nx;
  306.             niy = ny;
  307.             chi = i;
  308.              eatobj:
  309.             edog->eattime =
  310.                 moves + obj->quan * objects[obj->otyp].oc_delay;
  311.             if(edog->hungrytime < moves)
  312.                 edog->hungrytime = moves;
  313.             edog->hungrytime +=
  314.                 5*obj->quan * objects[obj->otyp].nutrition;
  315.             mtmp->mconf = 0;
  316.             if(cansee(nix,niy))
  317.                 pline("%s ate %s.", Monnam(mtmp), doname(obj));
  318.             /* perhaps this was a reward */
  319.             if(otyp != CADAVER)
  320.             edog->apport += 200/(edog->dropdist+moves-edog->droptime);
  321.             delobj(obj);
  322.             goto newdogpos;
  323.             }
  324.         nextobj:
  325.             obj = obj->nobj;
  326.         }
  327.  
  328.         for(j=0; j<MTSZ && j<cnt-1; j++)
  329.             if(nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
  330.                 if(rn2(4*(cnt-j))) goto nxti;
  331.  
  332. /* Some stupid C compilers cannot compute the whole expression at once. */
  333.         nearer = GDIST(nx,ny);
  334.         nearer -= GDIST(nix,niy);
  335.         nearer *= appr;
  336.         if((nearer == 0 && !rn2(++chcnt)) || nearer<0 ||
  337.             (nearer > 0 && !whappr &&
  338.                 ((omx == nix && omy == niy && !rn2(3))
  339.                 || !rn2(12))
  340.             )){
  341.             nix = nx;
  342.             niy = ny;
  343.             if(nearer < 0) chcnt = 0;
  344.             chi = i;
  345.         }
  346.     nxti:    ;
  347.     }
  348. newdogpos:
  349.     if(nix != omx || niy != omy){
  350.         if(info[chi] & ALLOW_U){
  351.             (void) hitu(mtmp, d(mdat->damn, mdat->damd)+1);
  352.             return(0);
  353.         }
  354.         mtmp->mx = nix;
  355.         mtmp->my = niy;
  356.         for(j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1];
  357.         mtmp->mtrack[0].x = omx;
  358.         mtmp->mtrack[0].y = omy;
  359.     }
  360.     if(mintrap(mtmp) == 2)    /* he died */
  361.         return(2);
  362.     pmon(mtmp);
  363.     return(1);
  364. }
  365.  
  366. /* return roomnumber or -1 */
  367. inroom(x,y) xchar x,y; {
  368. #ifndef QUEST
  369.     register struct mkroom *croom = &rooms[0];
  370.     while(croom->hx >= 0){
  371.         if(croom->hx >= x-1 && croom->lx <= x+1 &&
  372.            croom->hy >= y-1 && croom->ly <= y+1)
  373.             return(croom - rooms);
  374.         croom++;
  375.     }
  376. #endif QUEST
  377.     return(-1);    /* not in room or on door */
  378. }
  379.  
  380. tamedog(mtmp, obj)
  381. register struct monst *mtmp;
  382. register struct obj *obj;
  383. {
  384.     register struct monst *mtmp2;
  385.  
  386.     if(flags.moonphase == FULL_MOON && night() && rn2(6))
  387.         return(0);
  388.  
  389.     /* If we cannot tame him, at least he's no longer afraid. */
  390.     mtmp->mflee = 0;
  391.     mtmp->mfleetim = 0;
  392.     if(mtmp->mtame || mtmp->mfroz ||
  393. #ifndef NOWORM
  394.         mtmp->wormno ||
  395. #endif NOWORM
  396.         mtmp->isshk || mtmp->isgd || index(" &@12", mtmp->data->mlet))
  397.         return(0); /* no tame long worms? */
  398.     if(obj) {
  399.         if(dogfood(obj) >= MANFOOD) return(0);
  400.         if(cansee(mtmp->mx,mtmp->my)){
  401.             pline("%s devours the %s.", Monnam(mtmp),
  402.                 objects[obj->otyp].oc_name);
  403.         }
  404.         obfree(obj, (struct obj *) 0);
  405.     }
  406.     mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth);
  407.     *mtmp2 = *mtmp;
  408.     mtmp2->mxlth = sizeof(struct edog);
  409.     if(mtmp->mnamelth) (void) strcpy(NAME(mtmp2), NAME(mtmp));
  410.     initedog(mtmp2);
  411.     replmon(mtmp,mtmp2);
  412.     return(1);
  413. }
  414.